/**
 * CalendarView for jQuery
 *
 * Based on CalendarView for Prototype http://calendarview.org/ which is based
 * on Dynarch DHTML Calendar http://www.dynarch.com/projects/calendar/old/.
 *
 * CalendarView is licensed under the terms of the GNU Lesser General
 * Public License (LGPL)
 *
 * Usage:
 *   jQuery(document).ready(function() {
 *     $('#date_input').calendar();
 *   }
 *
 *   jQuery(document).ready(function() {
 *     $('#date_input').calendar({triggerElement: '#date_input_trigger'});
 *   }
 *
 *   jQuery(document).ready(function() {
 *     $('#date_input').calendar({parentElement: '#calendar_container'});
 *   }
 *
 * Default options:
 *   triggerElement: null, // Popup calendar
 *   parentElement: null, // Inline calendar
 *   minYear: 1900,
 *   maxYear: 2100,
 *   firstDayOfWeek: 1, // Monday
 *   weekend: "0,6", // Sunday and Saturday
 *   dateFormat: '%Y-%m-%d',
 *   selectHandler: null, // Will use default select handler
 *   closeHandler: null // Will use default close handler
 */
;(function($) {
    var Calendar = function() {
        this.date = new Date();
    };

    //------------------------------------------------------------------------------
    // Constants
    //------------------------------------------------------------------------------

    Calendar.VERSION = '1.2';
    Calendar.TODAY = 'Today';

    Calendar.DAY_NAMES = new Array(
		'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
	);

    Calendar.SHORT_DAY_NAMES = new Array('Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa');

    Calendar.MONTH_NAMES = new Array(
		'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
		'September', 'October', 'November', 'December'
	);

    Calendar.SHORT_MONTH_NAMES = new Array(
		'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
	);

    Calendar.NAV_PREVIOUS_YEAR = -2;
    Calendar.NAV_PREVIOUS_MONTH = -1;
    Calendar.NAV_TODAY = 0;
    Calendar.NAV_NEXT_MONTH = 1;
    Calendar.NAV_NEXT_YEAR = 2;

    //------------------------------------------------------------------------------
    // Static Methods
    //------------------------------------------------------------------------------

    /**
    * This gets called when the user presses a mouse button anywhere in the
    * document, if the calendar is shown. If the click was outside the open
    * calendar this function closes it.
    *
    * @param event
    */
    Calendar._checkCalendar = function(event) {
        if (!window._popupCalendar) {
            return false;
        }

        if ($(event.target).parents().index($(window._popupCalendar.container)) >= 0) {
            return false;
        }

        window._popupCalendar.callCloseHandler();
        return event.preventDefault();
    }

    /**
    * Event Handlers
    * @param event
    */
    Calendar.handleMouseDownEvent = function(event) {
        $(document).mouseup(Calendar.handleMouseUpEvent);
        event.preventDefault();
    }

    /**
    * Clicks of different actions
    * @param event
    */
    Calendar.handleMouseUpEvent = function(event) {
        var el = event.target;
        var calendar = el.calendar;
        var isNewDate = false;

        // If the element that was clicked on does not have an associated Calendar
        // object, return as we have nothing to do.
        if (!calendar) return false

        // Clicked on a day
        if (typeof el.navAction == 'undefined') {
            if (calendar.currentDateElement) {
                //calendar.currentDateElement.removeClass('selected');
                $(el).addClass('selected');
                calendar.shouldClose = (calendar.currentDateElement == $(el));
                if (!calendar.shouldClose) {
                    calendar.currentDateElement = $(el);
                }
            }
            calendar.date.setDateOnly(el.date);
            isNewDate = true;
            calendar.shouldClose = !$(el).hasClass('otherDay');
            var isOtherMonth = !calendar.shouldClose;
            if (isOtherMonth) {
                calendar.update(calendar.date);
            }
        } else {
            // Clicked on an action button
            var date = new Date(calendar.date);

            if (el.navAction == Calendar.NAV_TODAY) {
                date.setDateOnly(new Date());
            }

            var year = date.getFullYear();
            var mon = date.getMonth();
            function setMonth(m) {
                var day = date.getDate();
                var max = date.getMonthDays(m);
                if (day > max) date.setDate(max)
                date.setMonth(m);
            }
            switch (el.navAction) {

                // Previous Year                  
                case Calendar.NAV_PREVIOUS_YEAR:
                    if (year > calendar.minYear)
                        date.setFullYear(year - 1);
                    break;

                // Previous Month                  
                case Calendar.NAV_PREVIOUS_MONTH:
                    if (mon > 0) {
                        setMonth(mon - 1);
                    }
                    else if (year-- > calendar.minYear) {
                        date.setFullYear(year);
                        setMonth(11);
                    }
                    break;

                // Today                  
                case Calendar.NAV_TODAY:
                    break;

                // Next Month                  
                case Calendar.NAV_NEXT_MONTH:
                    if (mon < 11) {
                        setMonth(mon + 1);
                    }
                    else if (year < calendar.maxYear) {
                        date.setFullYear(year + 1);
                        setMonth(0);
                    }
                    break;

                // Next Year                  
                case Calendar.NAV_NEXT_YEAR:
                    if (year < calendar.maxYear)
                        date.setFullYear(year + 1);
                    break;

            }

            if (!date.equalsTo(calendar.date)) {
                calendar.shouldClose = false;
                calendar.setDate(date);
                isNewDate = true;
            } else if (el.navAction == 0) {
                isNewDate = (calendar.shouldClose = true);
            }
        }

        if (isNewDate) event && calendar.callSelectHandler();
        if (calendar.shouldClose) event && calendar.callCloseHandler();
        $(document).unbind('mouseup', Calendar.handleMouseUpEvent);
        return event.preventDefault();
    };

    Calendar.defaultSelectHandler = function(calendar) {
        if (!calendar.dateField) {
            return false;
        }

        // Update dateField value
        (calendar.dateField.attr('tagName') == 'INPUT')
			? calendar.dateField.val(calendar.date.print(calendar.dateFormat))
			: calendar.dateField.html(calendar.date.print(calendar.dateFormat));

        // Trigger the onchange callback on the dateField, if one has been defined
        calendar.dateField.trigger('change');

        // Call the close handler, if necessary
        if (calendar.shouldClose) {
            calendar.callCloseHandler();
        }

        return true;
    }

    Calendar.defaultCloseHandler = function(calendar) {
        calendar.hide();
    }

    //------------------------------------------------------------------------------
    // Calendar Instance
    //------------------------------------------------------------------------------

    Calendar.prototype = {
        // The HTML Container Element
        container: null,

        // Dates
        date: null,
        currentDateElement: null,

        // Status
        shouldClose: false,
        isPopup: true,

        /**
        * Update / (Re)initialize Calendar
        * @param date
        */
        update: function(date) {
            var calendar = this;
            var today = new Date();
            var thisYear = today.getFullYear();
            var thisMonth = today.getMonth();
            var thisDay = today.getDate();
            var month = date.getMonth();
            var dayOfMonth = date.getDate();
            var eventDates = this.eventDates;
            // Ensure date is within the defined range
            if (date.getFullYear() < this.minYear) {
                date.setFullYear(this.minYear);
            } else if (date.getFullYear() > this.maxYear) {
                date.setFullYear(this.maxYear);
            }
            this.date = new Date(date);

            // Calculate the first day to display (including the previous month)
            date.setDate(1);
            var day1 = (date.getDay() - this.firstDayOfWeek) % 7;
            if (day1 < 0) day1 += 7;
            date.setDate(-day1);
            date.setDate(date.getDate() + 1);

            // Fill in the days of the month
            $('tbody tr', this.container).each(function() {
                var rowHasDays = false;
                $(this).children().each(function() {
                    var day = date.getDate();

                    var dayOfWeek = date.getDay();
                    var isCurrentMonth = (date.getMonth() == month);

                    // Reset classes on the cell
                    cell = $(this);
                    cell.removeAttr('class');
                    cell[0].date = new Date(date);
                    cell.html(day);

                    // Account for days of the month other than the current month
                    if (!isCurrentMonth) {
                        cell.addClass('otherDay');
                    } else {
                        rowHasDays = true;
                    }
                    //var isSelectedDate = selectedDates.join(indexOf(day.toDateString()));
                    // Ensure the current day is selected
                    //                    if (isCurrentMonth && (day == dayOfMonth)) {
                    //                        cell.addClass('selected');
                    //                        calendar.currentDateElement = cell;
                    //                    }
                    // Highlight selected dates
                    for (i = 0; i < eventDates.length; i++) {
                        var isSelectedCurrentMonth = (eventDates[i].getMonth() == month);
                        if (isCurrentMonth && isSelectedCurrentMonth && day == eventDates[i].getDate()) {
                            cell.addClass('selected');
                            calendar.currentDateElement = cell;
                        }
                    }

                    // Today
                    if (date.getFullYear() == thisYear && date.getMonth() == thisMonth && day == thisDay) {
                        cell.addClass('today');
                    }

                    // Weekend
                    if (calendar.weekend.indexOf(dayOfWeek.toString()) != -1) {
                        cell.addClass('weekend');
                    }

                    // Set the date to tommorrow
                    date.setDate(day + 1);
                });
                // Hide the extra row if it contains only days from another month
                !rowHasDays ? $(this).hide() : $(this).show();
            });

            $('td.title', this.container).html(Calendar.MONTH_NAMES[month] + ' ' + calendar.date.getFullYear());
        },

        create: function(parent) {

            // If no parent was specified, assume that we are creating a popup calendar.
            this.isPopup = false;
            if (!parent) {
                parent = $('body');
                this.isPopup = true;
            }

            // Calendar Table
            var table = $('<table />');

            // Calendar Header
            var thead = $('<thead />');
            table.append(thead);

            // Title Placeholder
            var row = $('<tr />');
            var cell = $('<td colspan="7" class="title" />');
            row.append(cell);
            thead.append(row);

            // Calendar Navigation
            row = $('<tr />');
            this._drawButtonCell(row, '&#x00ab;', 1, Calendar.NAV_PREVIOUS_YEAR);
            this._drawButtonCell(row, '&#x2039;', 1, Calendar.NAV_PREVIOUS_MONTH);
            this._drawButtonCell(row, Calendar.TODAY, 3, Calendar.NAV_TODAY);
            this._drawButtonCell(row, '&#x203a;', 1, Calendar.NAV_NEXT_MONTH);
            this._drawButtonCell(row, '&#x00bb;', 1, Calendar.NAV_NEXT_YEAR);
            thead.append(row);

            // Day Names
            row = $('<tr />');
            for (var i = 0; i < 7; ++i) {
                var realDay = (i + this.firstDayOfWeek) % 7;
                cell = $('<th />').html(Calendar.SHORT_DAY_NAMES[realDay]);
                if (this.weekend.indexOf(realDay.toString()) != -1)
                    cell.addClass('weekend');
                row.append(cell);
            }
            thead.append(row);

            // Calendar Days
            var tbody = table.append($('<tbody />'));
            for (i = 6; i > 0; --i) {
                row = $('<tr />').addClass('days');
                tbody.append(row);
                for (var j = 7; j > 0; --j) {
                    cell = $('<td />');
                    cell[0].calendar = this;
                    row.append(cell);
                }
            }

            // Calendar Container (div)
            this.container = $('<div />').addClass('calendar').append(table);
            if (this.isPopup) {
                this.container.css({
                    position: 'absolute',
                    display: 'none'
                }).addClass('popup');
            }

            // Initialize Calendar
            this.update(this.date);

            // Observe the container for mousedown events
            this.container.mousedown(Calendar.handleMouseDownEvent);

            // Append to parent element
            parent.append(this.container);
        },

        _drawButtonCell: function(parent, text, colSpan, navAction) {
            var cell = $('<td />');
            if (colSpan > 1) cell[0].colSpan = colSpan; // IE issue attr()
            cell.addClass('button').html(text).attr('unselectable', 'on'); // IE;
            cell[0].calendar = this;
            cell[0].navAction = navAction;
            parent.append(cell);
            return cell;
        },

        //------------------------------------------------------------------------------
        // Callbacks
        //------------------------------------------------------------------------------

        /**
        * Calls the Select Handler (if defined)
        */
        callSelectHandler: function() {
            if (this.selectHandler) {
                this.selectHandler(this, this.date.print(this.dateFormat));
            }
        },

        /**
        * Calls the Close Handler (if defined)
        */
        callCloseHandler: function() {
            if (this.closeHandler) {
                this.closeHandler(this);
            }
        },

        //------------------------------------------------------------------------------
        // Calendar Display Functions
        //------------------------------------------------------------------------------

        /**
        * Shows the Calendar
        */
        show: function() {
            this.container.show();
            if (this.isPopup) {
                window._popupCalendar = this;
                $(document).mousedown(Calendar._checkCalendar);
            }
        },

        /**
        * Shows the calendar at the given absolute position
        * @param x
        * @param y
        */
        showAt: function(x, y) {
            this.container.css({
                left: x + 'px',
                top: y + 'px'
            })
            this.show();
        },

        /**
        * Shows the Calendar at the coordinates of the provided element
        * @param element
        */
        showAtElement: function(element) {
            var offset = element.offset();
            this.showAt(offset.left, offset.top);
        },

        /**
        * Hides the Calendar
        */
        hide: function() {
            if (this.isPopup) {
                $(document).unbind('mousedown', Calendar._checkCalendar);
            }
            this.container.hide();
        },

        /**
        * Tries to identify the date represented in a string.  If successful it also
        * calls this.setDate which moves the calendar to the given date.
        * @param str
        * @param format
        */
        parseDate: function(str, format) {
            if (!format) {
                format = this.dateFormat;
            }
            this.setDate(Date.parseDate(str, format));
        },

        setDate: function(date) {
            if (!date.equalsTo(this.date))
                this.update(date);
        },

        setRange: function(minYear, maxYear) {
            this.minYear = minYear;
            this.maxYear = maxYear;
        }
    }

    // global object that remembers the calendar
    window._popupCalendar = null;

    //==============================================================================
    // Date Object Patches
    // This is pretty much untouched from the original.
    //==============================================================================
    Date.DAYS_IN_MONTH = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    Date.SECOND = 1000; /* milliseconds */
    Date.MINUTE = 60 * Date.SECOND;
    Date.HOUR = 60 * Date.MINUTE;
    Date.DAY = 24 * Date.HOUR;
    Date.WEEK = 7 * Date.DAY;

    // Parses Date
    Date.parseDate = function(str, fmt) {
        var today = new Date();
        var y = 0;
        var m = -1;
        var d = 0;
        var a = str.split(/\W+/);
        var b = fmt.match(/%./g);
        var i = 0, j = 0;
        var hr = 0;
        var min = 0;

        for (i = 0; i < a.length; ++i) {
            if (!a[i]) continue;
            switch (b[i]) {
                case "%d":
                case "%e":
                    d = parseInt(a[i], 10);
                    break;
                case "%m":
                    m = parseInt(a[i], 10) - 1;
                    break;
                case "%Y":
                case "%y":
                    y = parseInt(a[i], 10);
                    (y < 100) && (y += (y > 29) ? 1900 : 2000);
                    break;
                case "%b":
                case "%B":
                    for (j = 0; j < 12; ++j) {
                        if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) {
                            m = j;
                            break;
                        }
                    }
                    break;
                case "%H":
                case "%I":
                case "%k":
                case "%l":
                    hr = parseInt(a[i], 10);
                    break;
                case "%P":
                case "%p":
                    if (/pm/i.test(a[i]) && hr < 12)
                        hr += 12;
                    else if (/am/i.test(a[i]) && hr >= 12)
                        hr -= 12;
                    break;
                case "%M":
                    min = parseInt(a[i], 10);
                    break;
            }
        }
        if (isNaN(y)) y = today.getFullYear();
        if (isNaN(m)) m = today.getMonth();
        if (isNaN(d)) d = today.getDate();
        if (isNaN(hr)) hr = today.getHours();
        if (isNaN(min)) min = today.getMinutes();
        if (y != 0 && m != -1 && d != 0)
            return new Date(y, m, d, hr, min, 0);
        y = 0; m = -1; d = 0;
        for (i = 0; i < a.length; ++i) {
            if (a[i].search(/[a-zA-Z]+/) != -1) {
                var t = -1;
                for (j = 0; j < 12; ++j) {
                    if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) {
                        t = j; break;
                    }
                }
                if (t != -1) {
                    if (m != -1) {
                        d = m + 1;
                    }
                    m = t;
                }
            } else if (parseInt(a[i], 10) <= 12 && m == -1) {
                m = a[i] - 1;
            } else if (parseInt(a[i], 10) > 31 && y == 0) {
                y = parseInt(a[i], 10);
                (y < 100) && (y += (y > 29) ? 1900 : 2000);
            } else if (d == 0) {
                d = a[i];
            }
        }
        if (y == 0)
            y = today.getFullYear();
        if (m != -1 && d != 0)
            return new Date(y, m, d, hr, min, 0);
        return today;
    };

    // Returns the number of days in the current month
    Date.prototype.getMonthDays = function(month) {
        var year = this.getFullYear()
        if (typeof month == "undefined")
            month = this.getMonth()
        if (((0 == (year % 4)) && ((0 != (year % 100)) || (0 == (year % 400)))) && month == 1)
            return 29
        else
            return Date.DAYS_IN_MONTH[month]
    };

    // Returns the number of day in the year
    Date.prototype.getDayOfYear = function() {
        var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
        var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
        var time = now - then;
        return Math.floor(time / Date.DAY);
    };

    /** Returns the number of the week in year, as defined in ISO 8601. */
    Date.prototype.getWeekNumber = function() {
        var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
        var DoW = d.getDay();
        d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
        var ms = d.valueOf(); // GMT
        d.setMonth(0);
        d.setDate(4); // Thu in Week 1
        return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
    };

    /** Checks date and time equality */
    Date.prototype.equalsTo = function(date) {
        return ((this.getFullYear() == date.getFullYear()) &&
			(this.getMonth() == date.getMonth()) &&
			(this.getDate() == date.getDate()) &&
			(this.getHours() == date.getHours()) &&
			(this.getMinutes() == date.getMinutes()));
    };

    /** Set only the year, month, date parts (keep existing time) */
    Date.prototype.setDateOnly = function(date) {
        var tmp = new Date(date);
        this.setDate(1);
        this.setFullYear(tmp.getFullYear());
        this.setMonth(tmp.getMonth());
        this.setDate(tmp.getDate());
    };

    /** Prints the date in a string according to the given format. */
    Date.prototype.print = function(str) {
        var m = this.getMonth();
        var d = this.getDate();
        var y = this.getFullYear();
        var wn = this.getWeekNumber();
        var w = this.getDay();
        var s = {};
        var hr = this.getHours();
        var pm = (hr >= 12);
        var ir = (pm) ? (hr - 12) : hr;
        var dy = this.getDayOfYear();
        if (ir == 0)
            ir = 12;
        var min = this.getMinutes();
        var sec = this.getSeconds();
        s["%a"] = Calendar.SHORT_DAY_NAMES[w]; // abbreviated weekday name [FIXME: I18N]
        s["%A"] = Calendar.DAY_NAMES[w]; // full weekday name
        s["%b"] = Calendar.SHORT_MONTH_NAMES[m]; // abbreviated month name [FIXME: I18N]
        s["%B"] = Calendar.MONTH_NAMES[m]; // full month name
        // FIXME: %c : preferred date and time representation for the current locale
        s["%C"] = 1 + Math.floor(y / 100); // the century number
        s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
        s["%e"] = d; // the day of the month (range 1 to 31)
        // FIXME: %D : american date style: %m/%d/%y
        // FIXME: %E, %F, %G, %g, %h (man strftime)
        s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
        s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
        s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
        s["%k"] = hr;   // hour, range 0 to 23 (24h format)
        s["%l"] = ir;   // hour, range 1 to 12 (12h format)
        s["%m"] = (m < 9) ? ("0" + (1 + m)) : (1 + m); // month, range 01 to 12
        s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
        s["%n"] = "\n";   // a newline character
        s["%p"] = pm ? "PM" : "AM";
        s["%P"] = pm ? "pm" : "am";
        // FIXME: %r : the time in am/pm notation %I:%M:%S %p
        // FIXME: %R : the time in 24-hour notation %H:%M
        s["%s"] = Math.floor(this.getTime() / 1000);
        s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
        s["%t"] = "\t";   // a tab character
        // FIXME: %T : the time in 24-hour notation (%H:%M:%S)
        s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
        s["%u"] = w + 1;  // the day of the week (range 1 to 7, 1 = MON)
        s["%w"] = w;    // the day of the week (range 0 to 6, 0 = SUN)
        // FIXME: %x : preferred date representation for the current locale without the time
        // FIXME: %X : preferred time representation for the current locale without the date
        s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
        s["%Y"] = y;    // year with the century
        s["%%"] = "%";    // a literal '%' character

        var re = /%./g;
        var a = str.match(re);
        for (var i = 0; i < a.length; i++) {
            var tmp = s[a[i]];
            if (tmp) {
                re = new RegExp(a[i], 'g');
                str = str.replace(re, tmp);
            }
        }

        return str;
    };

    Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear;
    Date.prototype.setFullYear = function(y) {
        var d = new Date(this);
        d.__msh_oldSetFullYear(y);
        if (d.getMonth() != this.getMonth())
            this.setDate(28);
        this.__msh_oldSetFullYear(y);
    }

    //------------------------------------------------------------------------------
    // The jQuery plugin function
    //------------------------------------------------------------------------------
    $.fn.calendar = function(options) {
        var defaults = {
            triggerElement: null, // Popup calendar
            parentElement: null, // Inline calendar
            minYear: 1900,
            maxYear: 2100,
            firstDayOfWeek: 1, // Monday
            weekend: "0,6", // Sunday and Saturday
            dateFormat: '%Y-%m-%d',
            dateField: null,
            selectHandler: null,
            closeHandler: null,
            eventDates: null
        };
        var settings = $.extend({}, defaults, options);

        this.each(function() {
            var self = $(this);
            var calendar = new Calendar();

            calendar.minYear = settings.minYear;
            calendar.maxYear = settings.maxYear;

            calendar.firstDayOfWeek = settings.firstDayOfWeek;
            calendar.weekend = settings.weekend;
            calendar.dateFormat = settings.dateFormat;
            calendar.dateField = (settings.dateField || self);

            calendar.selectHandler = (settings.selectHandler || Calendar.defaultSelectHandler);
            calendar.eventDates = settings.eventDates;

            // Inline Calendar
            var selfDate = self.html() || self.val();
            if (settings.parentElement) {
                calendar.create($(settings.parentElement));
                if (selfDate) calendar.parseDate(selfDate);
                calendar.show();
            } else {
                // Popup Calendar
                calendar.create();
                if (selfDate) calendar.parseDate(selfDate);
                var triggerElement = $(settings.triggerElement || self);
                triggerElement.click(function() {
                    calendar.closeHandler = (settings.closeHandler || Calendar.defaultCloseHandler);
                    calendar.showAtElement(triggerElement);
                });
            }
        });

        return this;
    }

})(jQuery);
